<?php

namespace App\Http\Controllers;

use Illuminate\Database\Eloquent\Collection;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;

class Controller extends BaseController
{
  use AuthorizesRequests;
  use DispatchesJobs;
  use ValidatesRequests;

  protected $model;
  protected $resource;

  public function __construct(Request $request, string $model, string $resource)
  {
    $this->model = 'App\\Models\\' . $model;
    $this->resource = 'App\\Http\\Resources\\' . $resource;
  }

  /**
   * Display a listing of the resource.
   *
   * Acceptable qry operators are:
   * - eq for equal (=)
   * - gt for greater than (>)
   * - lt for less than (<)
   * - lk for like (like)
   * They shall be provided in square brackets soon after the equal sign before the value (see examples)
   * If you provide none equal will be used
   * Acceptable qry options are:
   * - sort for order by (default=id)
   * - direction for order by option (default=asc)
   * - limit for pagination (defalut=10)
   * - page for pagination (default=1)
   * - include for getting related models (default=null)
   *   To include more than one relationship you have to pass
   *   the parameter this way: ?include[]=relationship1&include[]=relationship2
   *   To include nested relationships you have to pass
   *   the parameter this way: ?include[]=relationship1.relationship2
   *
   * see config/parameters.php
   *
   * Url example:
   * http://localhost:8000/api/v1/roles?name=[lk]er&sort=slug&direction=desc
   * http://localhost:8000/api/v1/roles?name=[lk]er&sort=slug&direction=desc&limit=1&page=2
   * http://localhost:8000/api/v1/roles?slug=reader
   * http://localhost:8000/api/v1/roles?slug=reader&include=permissions
   * http://localhost:8000/api/v1/locales/1?include[]=country&include[]=language
   */
  public function index(Request $request)
  {
    Log::debug(__METHOD__);

    $models = $params = $qryoptions = $qryparams = $fields = [];

    if (!$request->exists('limit')) {
      $request->request->add(['paginate' => config('coreapi.index_limit')]);
    }
    $params = $request->all();
    $qryoptions = config('parameters.foreseen');
    if (isset($params['sort'])) {
      $qryoptions['sort'] = $params['sort'];
    }
    if (isset($params['direction'])) {
      $qryoptions['direction'] = $params['direction'];
    }
    if (isset($params['limit'])) {
      $qryoptions['limit'] = $params['limit'];
    }
    if (isset($params['page'])) {
      $qryoptions['page'] = $params['page'];
    }
    if (isset($params['include'])) {
      $qryoptions['include'] = $params['include'];
    }
    if (isset($params['locale'])) {
      $qryoptions['locale'] = $params['locale'];
    }
    $fields = array_diff($params, $qryoptions);
    $qryparams = create_qry_params($fields);

    if (isset($qryoptions['include'])) {
      $models = $this->model::where($qryparams)
        ->with($qryoptions['include'])
        ->orderBy($qryoptions['sort'], $qryoptions['direction'])
        ->paginate($qryoptions['limit']);
    } else {
      $models = $this->model::where($qryparams)
        ->orderBy($qryoptions['sort'], $qryoptions['direction'])
        ->paginate($qryoptions['limit']);
    }

    return $this->resource::collection($models);
  }

  public function store(Request $request)
  {
    Log::debug(__METHOD__);

    $newobj = $newresource = $validator = $response = null;

    $validator = Validator::make($request->all(), $this->model::$insertRules);
    if ($validator->fails()) {
      $response = response()->json(['error' => $validator->errors()], 400);
    } else {
      $newobj = $this->model::create($request->all());
      $newobj->update(['active' => true]);
      // $newobj = $this->model::find($newobj->id);
      $newresource = new $this->resource($newobj);
      $response = response()->json([
        'resource' => $newresource,
        'message' => trans('coreapi.resource_created'),
      ], 201);
    }

    return $response;
  }

  public function show(Request $request, $id)
  {
    Log::debug(__METHOD__);

    $obj = $resource = null;
    $params = $qryparams = [];

    $params = $request->all();
    $qryparams = create_qry_params();
    if (isset($params['include'])) {
      $obj = $this->model::where($qryparams)
        ->with($params['include'])
        ->findOrFail($id);
    } else {
      $obj = $this->model::where($qryparams)
        ->findOrFail($id);
    }

    $resource = new $this->resource($obj);

    return response()->json([
      'resource' => $resource,
    ], 200);
  }

  public function update(Request $request, $id)
  {
    Log::debug(__METHOD__);

    $updobj = $updresource = $validator = $response = null;
    $qryparams = [];

    $qryparams = create_qry_params();
    $updobj = $this->model::where($qryparams)
      ->findOrFail($id);
    if ($request->all()) {
      $validator = Validator::make($request->all(), $this->model::$updatetRules);
      if ($validator->fails()) {
        $response = response()->json(['error' => $validator->errors()], 400);
      } else {
        $updobj->update($request->all());
        $updresource = new $this->resource($updobj);
        $response = response()->json([
          'resource' => $updresource,
          'message' => trans('coreapi.resource_updated'),
        ], 200);
      }
    } else {
      $response = response()->json(['message' => trans('coreapi.no_upd_vales')], 400);
    }

    return $response;
  }

  public function destroy($id)
  {
    Log::debug(__METHOD__);

    $delobj = $response = null;
    $qryparams = [];

    $qryparams = create_qry_params();
    $delobj = $this->model::where($qryparams)
      ->findOrFail($id);
    $delobj->delete();

    return response()->json([
      'success' => true,
      'status' => 200,
      'message' => trans('coreapi.resource_deleted'),
    ], 200);
  }
}
